package org.lc.eic.messageconstruct.requestreply.jaxb.impl;

import java.sql.Timestamp;
import java.util.GregorianCalendar;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import org.lc.eic.messageconstruct.jaxb.content.ContentDecoder;
import org.lc.eic.messageconstruct.jaxb.content.ContentEncoder;
import org.lc.eic.messageconstruct.jaxb.content.ContentMapper;

import org.lc.eic.messageconstruct.requestreply.jaxb.exception.JAXBRequestMappingException;
import org.lc.eic.messgeconstruct.requestreply.History;
import org.lc.eic.messgeconstruct.requestreply.HistoryEntry;
import org.lc.eic.messgeconstruct.requestreply.Request;
import org.lc.request._1_0.ContentType;
import org.lc.request._1_0.EntryType;
import org.lc.request._1_0.HistoryType;
import org.lc.request._1_0.ObjectFactory;
import org.lc.request._1_0.ReplyType;
import org.w3c.dom.Element;



public class JAXBRequestMapping<I> {
	
	
	private ContentMapper contentMapper = new ContentMapper();
	

	public void setContentMapper(ContentMapper contentMapper) {
		this.contentMapper = contentMapper;
	}



	public Request<I> toRequest(org.lc.request._1_0.Request jaxbRequest) throws Exception {

		Request<I> request = new Request<I>();

		request.setDestination(jaxbRequest.getDestination());
		request.setUniqueID(jaxbRequest.getUniqueID());
		
		ContentDecoder<I> contentDecoder = contentMapper.getContentDecoder(jaxbRequest.getContentType());
		
		if(contentDecoder == null){
			throw new JAXBRequestMappingException("No content-mapping found for content-type: "+jaxbRequest.getContentType());
		}
		
		
		request.setContent( contentDecoder.decodeContent(jaxbRequest.getContent().getAny()) );
				
		request.setContentType( request.getContent().getClass().getName() );

		request.setTimestamp(new Timestamp(jaxbRequest.getTimestamp()
				.toGregorianCalendar().getTimeInMillis()));

		request.setExpiration(new Timestamp(jaxbRequest.getExpiration()
				.toGregorianCalendar().getTimeInMillis()));

		Request.Reply reply = new Request.Reply();

		reply.setDestination(jaxbRequest.getReply().getDestination());
		reply.setCorrelationID(jaxbRequest.getReply().getCorrelationID());

		request.setReply(reply);

		History history = new History();

		for (Object obj : jaxbRequest.getHistory().getEntry()) {
			EntryType jaxbEntry = (EntryType) obj;

			HistoryEntry entry = new HistoryEntry();
			entry.setMessage(jaxbEntry.getMessage());

			entry.setTimestamp(new Timestamp(jaxbEntry.getTimestamp()
					.toGregorianCalendar().getTimeInMillis()));

			history.addEntry(entry);
		}

		request.setHistory(history);

		return request;

	}

	

	public org.lc.request._1_0.Request toJAXBRequest(Request request)
			throws Exception {

		ObjectFactory objFactory = new ObjectFactory();

		org.lc.request._1_0.Request jaxbRequest = objFactory.createRequest();

		jaxbRequest.setDestination(request.getDestination());
		jaxbRequest.setUniqueID(request.getUniqueID());

		ContentType jaxbContent = objFactory.createContentType();

		Object requestContent = request.getContent();
		
	
		
		ContentEncoder contentEncoder = null;
		
		if(request.getContentType() != null){
			contentEncoder = contentMapper.getContentEncoder(request.getContentType());
			
			if(contentEncoder == null){
				throw new JAXBRequestMappingException("No content-mapping found for content-type: "+request.getContentType());
			}
			
		} else{
			contentEncoder = contentMapper.getContentEncoder(request.getContent().getClass().getName());
			
			if(contentEncoder == null){
				throw new JAXBRequestMappingException("No content-mapping found for java-type: "+request.getContent().getClass().getName());
			}
		}
		
		
		Element elementContent = contentEncoder.encodeContent(requestContent);

		jaxbContent.setAny( elementContent );

		jaxbRequest.setContent(jaxbContent);
		jaxbRequest.setContentType(elementContent.getNamespaceURI());

		jaxbRequest.setTimestamp(mapTimestamp(request.getTimestamp()));
		jaxbRequest.setExpiration(mapTimestamp(request.getExpiration()));

		ReplyType reply = objFactory.createReplyType();
		reply.setDestination(request.getReply().getDestination());
		reply.setCorrelationID(request.getReply().getCorrelationID());

		jaxbRequest.setReply(reply);

		HistoryType jaxbHistory = objFactory.createHistoryType();

		for (HistoryEntry entry : request.getHistory().getEntries()) {

			EntryType jaxbEntry = objFactory.createEntryType();
			jaxbEntry.setMessage(entry.getMessage());

			jaxbEntry.setTimestamp(mapTimestamp(entry.getTimestamp()));

			jaxbHistory.getEntry().add(jaxbEntry);
		}

		jaxbRequest.setHistory(jaxbHistory);

		return jaxbRequest;

	}

	private XMLGregorianCalendar mapTimestamp(Timestamp timestamp) throws DatatypeConfigurationException {
	
		GregorianCalendar gregorianCalendar = new GregorianCalendar();
		gregorianCalendar.setTimeInMillis(timestamp.getTime());

		return DatatypeFactory.newInstance().newXMLGregorianCalendar(gregorianCalendar);
	}

}
